package cn.cmeizu.spring6.annotationaop.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @author cmeizu
 * @date 2023/2/12 16:41
 */
@Aspect //切面类
@Component  //ioc容器
public class LogAspect {

  /**
   * 设置切入点和通知类型
   * execution固定表达式
   * public 权限修饰符 * 表示所有
   * int 表示返回值
   * 方法参数: .. 表示任意参数
   * 切入点表达式: execution(访问修饰符 增强方法返回类型 增强方法所在类全路径.方法名称(方法参数))
   * 通知类型:
   * 前置：@Before(value="切入点表达式配置切入点")
   * 返回：@AfterReturning
   * 异常：@AfterThrowing
   * 后置：@After()
   * 环绕：@Around()
   */

  //重用切入点表达式
  @Pointcut(value = "execution(* cn.cmeizu.spring6.annotationaop.impl.*.*(..))")
  public void pointcut() {

  }


  //@Before(value = "execution(* cn.cmeizu.spring6.annotationaop.impl.CalculatorImpl.*(..))")
  //@Before(value = "execution(public int cn.cmeizu.spring6.annotationaop.impl.CalculatorImpl.*(..))")
  //@Before(value = "pointcut()") 同一个切面的情况
  @Before(value = "cn.cmeizu.spring6.annotationaop.aspect.LogAspect.pointcut()")
  public void beforeMethod(JoinPoint joinPoint) {
    String methodName = joinPoint.getSignature().getName();
    Object[] args = joinPoint.getArgs();
    System.out.println("Logger 前置通知! 方法名称: " + methodName + " 参数: " + Arrays.toString(args));
  }

  @After(value = "execution(* cn.cmeizu.spring6.annotationaop.impl.*.*(..))")
  public void afterMethod(JoinPoint joinPoint) {
    String methodName = joinPoint.getSignature().getName();
    Object[] args = joinPoint.getArgs();
    System.out.println("Logger 后置通知! 方法名称: " + methodName + " 参数: " + Arrays.toString(args));
  }

  @AfterReturning(value = "execution(* cn.cmeizu.spring6.annotationaop.impl.*.*(..))", returning = "result")
  public void afterReturningMethod(JoinPoint joinPoint, Object result) {
    String methodName = joinPoint.getSignature().getName();
    Object[] args = joinPoint.getArgs();
    System.out.println("Logger 返回通知! 方法名称: " + methodName + " 参数: " + Arrays.toString(args) + " 目标的返回结果: " + result);
  }

  @AfterThrowing(value = "execution(* cn.cmeizu.spring6.annotationaop.impl.*.*(..))", throwing = "ex")
  public void afterThrowingMethod(JoinPoint joinPoint, Throwable ex) {
    String methodName = joinPoint.getSignature().getName();
    Object[] args = joinPoint.getArgs();
    System.out.println("Logger 异常通知! 方法名称: " + methodName + " 参数: " + Arrays.toString(args) + " 目标的返回异常信息: " + ex);
  }

  @Around(value = "execution(* cn.cmeizu.spring6.annotationaop.impl.*.*(..))")
  public Object aroundMethod(ProceedingJoinPoint joinPoint) {
    String methodName = joinPoint.getSignature().getName();
    Object[] args = joinPoint.getArgs();
    Object result = null;
    try {
      System.out.println("Logger 环绕通知! 方法名称: " + methodName + " 参数: " + Arrays.toString(args));
      result = joinPoint.proceed();
      System.out.println("Logger 环绕通知! 方法执行之后");
    } catch (Throwable throwable) {
      throwable.printStackTrace();
      System.out.println("目标方法发生异常，执行环绕通知！");
    }finally {
      System.out.println("环绕通知，目标方法执行完成！");
    }
    return result;
  }
}
